﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Silvermoon.Controls.Base;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Panel that layouts it's controls vertically stacked and displays a scrollbar if necassary.
    /// If any control changes it's size, the layout is recreated.
    /// </summary>
    public class ScrollStackPanel : ScrollViewer
    {
        private int virtualHeight;
        private List<Control> controlsInView = new List<Control>();

        public ControlCollection Controls { get { return GetVisibleControls(); } }

        public override int VirtualHeight
        {
            get
            {
                return virtualHeight;
            }
        }

        protected override void OnLayout()
        {
            if (CheckFlag(InvalidationFlag.Size | InvalidationFlag.Layout)) LayoutControls();

            base.OnLayout();
        }


        private bool layouting = false;

        private  void LayoutControls()
        {
            layouting = true;
            controlsInView.Clear();
            InvalidationFlag mask = InvalidationMask;
            this.InvalidationMask = InvalidationFlag.Empty;
            Control c = VisibleControls.First;
            int top = -yOffset;
            int w = ClientWidth;
            while (c != null)
            {
                if (!IsScrollbar(c) && c.Visible)
                {
                    Rectangle rect = new Rectangle(0, 0, c.Width, c.Height);
                    Rectangle bounds = c.Margin.Layout(rect, new Size(w, c.PaddingHeight));
                    bounds.Y += top;
                    if (IsInView(bounds))
                    {
                        c.Bounds = bounds;
                        controlsInView.Add(c);
                        c.PreLoad();
                    }
                    top += c.PaddingHeight;
                }
                c = c.NextControl;
            }
            virtualHeight = top + yOffset;
            layouting = false;
            InvalidationMask = mask;
            if (virtualHeight < ClientHeight && yOffset != 0) EnsureRestState(true);
        }

        private bool IsInView(Rectangle bounds)
        {
            if (bounds.Bottom <= 0) return false;
            return bounds.Top < ClientHeight;
        }

        protected override void RenderChildren(Silvermoon.Core.Renderer renderer)
        {
            Rectangle scissorBox = renderer.ScissorBox;
            renderer.RenderControls(controlsInView.ToArray());
            if (IsScrollbarAvailable) renderer.RenderControl(ScrollBar);
            renderer.ScissorBox = scissorBox;
        }

        protected override void OnChildSizeChanged(Control child, Size oldSize)
        {
            if (!layouting)
            {
                if (child.Height != oldSize.Height)
                {
                    Invalidate(InvalidationFlag.Layout);
                }
            }
        }


        protected override void OnChildVisibleChanged(Control child)
        {
            if (!layouting && !IsScrollbar(child))
            {
                Invalidate(InvalidationFlag.Layout);
            }
        }


        public override void BringIntoView(Rectangle bounds, bool animated)
        {
            bounds.Y += yOffset;
            base.BringIntoView(bounds, animated);
        }

        protected internal override void OnTap(TapEventArgs e)
        {
            base.OnTap(e);
            e.Handled = true;
        }

        protected internal override IEnumerable<Control> GetAttachedChildren()
        {
            return controlsInView;
        }

    }
}
